/*=============================================================================
#    The element-comm is a tentative program used to test our ideas.           
#                       Copyright (C)  bgao                                    
#
#     This program is free software; you can redistribute it and/or            
#      modify it under the terms of the GNU General Public License             
#     as published by the Free Software Foundation; either version 2           
#         of the License, or (at your option) any later version.               
#
#     This program is distributed in the hope that it will be useful,          
#    but WITHOUT ANY WARRANTY; without even the implied warranty of           
#     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            
#             GNU General Public License for more details.                    
#
#    You should have received a copy of the GNU General Public License        
#     along with this program; if not, write to the Free Software             
#      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,             
#                       MA  02110-1301, USA.                                  
#==============================================================================
# $Id: mac_info.c 348 2010-11-29 09:01:16Z bgao $ 
#
# $Author: bgao $ 
#
# $Revision: 348 $ 
#
# $Date: 2010-11-29 17:01:16 +0800 (星期一, 29 十一月 2010) $ 
#
# Description: 
#
=============================================================================*/
/*! @file mac_info.c
 *  @brief This module implements initilization, get, check
 *         and set functions of the MAC layer's constants.
 */
#include "mac.h"

/*! the MAC information base, which hold most of the MAC constant */
static pib_t pib;
/*! the MAC contrl block instant */
static mac_cb_t mcb;

/*! the 64-bits extended address */
uint64 aExtendedAddress = 0x12345678;

/*! initialize the mac_info related constant */
int8 mac_info_init(void)
{
    mac_pib_init();
    mac_mcb_init();
    rf_disable_addr_recg();

    return MAC_OK;
}

/*! initialize the information base related constant */
int8 mac_pib_init(void)
{
    mac_sup_frm_t sv;
    uint16 value;
    /* active scan's results are reported through mlme beacon notify */
    pib.mac_auto_request = 0;
    /* set superframe value */
    pib.mac_min_be = 3;
    pib.mac_max_be = 5;
    pib.mac_max_csma_backoffs = 4;
    pib.mac_max_frame_retries = 3;
    /* where 6 represents the number of PHY header octets plus the number of PSDU octets in an
     * acknowledgment frame.
     */
    /* aUnitBackoffPeriod + aTurnaroundTime + phy_get_shr_duration() + 2*phy_get_symbol_per_octet() */
    pib.mac_ack_wait_duration = SYMBOL_TO_TICK(46);

    pib.mac_pan_id = 0xffff;
    pib.mac_short_addr = USING_EXTENDED_ADDR;/*0xffff;*/


    pib.mac_associated_pan_coord = false;
    pib.mac_association_permit = false;
    pib.mac_coord_short_addr = 0xffff;
    pib.mac_dsn = 0; /* TODO: should get a random number */
    pib.mac_gts_permit = false;
    pib.mac_max_frame_total_wait_time = SYMBOL_TO_TICK(1026); /* set according to eaqution(14) of 802.15.4. */

    pib.mac_promiscuous_mode = false;
    pib.mac_response_wait_time = SYMBOL_TO_TICK(32);
    pib.mac_rx_on_when_idle = false; 
    pib.mac_security_enabled = false;
    pib.mac_transaction_persistence_time = SYMBOL_TO_TICK(0x01f4);

    pib.mac_beacon_order = 15;
    pib.mac_superframe_order = 0;
    /* the superframe order should be ignored when beacon order equals to 15 */
    pib.mac_association_permit = true;
    pib.mac_associated_pan_coord = true; /* indication of whether the device is associated to the PAN through the PAN coordinator */


    sv.bcn_order = mac_get_beacon_order();
    sv.sup_frm_order = mac_get_superframe_order();
    sv.fnl_cap_slot = 0;
    sv.ble = 0;
    sv.pan_coord = mac_get_associated_pan_coord();
    sv.assoc_pmit = mac_get_association_premit();
    value = mac_gen_sup_frm(&sv);
    mac_set_sup_frm_value(value);

    aExtendedAddress = (uint64)rf_get_rand();

    return MAC_OK;
}

/*! initialize the MAC control block */
int8 mac_mcb_init(void)
{
    return mac_set_state(mac_idle);
}

/*! set the state of MAC, the MAC have 6 states, which are defined
 *  in mac_state_t enumeration.
 *  @param stat the state to be set.
 *  @return return the result of this operation.
 */
int8 mac_set_state(mac_state_t stat)
{
    mcb.state = stat;

    return MAC_OK;
}

/*! get the current state of MAC.
 *  @return return the state of MAC.
 */
int8 mac_get_state(void)
{
    return mcb.state;
}

/*! set 64-bits extended address of the MAC.
 *  @param addr the 64-bits address to be set.
 *  @return returns the result of this operation.
 */
int8 mac_set_extended_addr(uint64 addr)
{
    aExtendedAddress = addr;

    return MAC_OK;
}

/*! get the PAN id of the MAC.
 *  @return the PAN id.
 */
uint16 mac_get_pan_id(void)
{
    return pib.mac_pan_id;
}

/*! set the PAN id of the MAC.
 *  @return the result of this operation.
 */
int8 mac_set_pan_id(uint16 pan_id)
{
    pib.mac_pan_id = pan_id;
    
    return MAC_OK;
}

/*! get the data sequence number, which is a vlaue incremented
 *  automatically when each time to get.
 *  @return return the data sequence number.
 */
uint8 mac_get_dsn(void)
{
    return pib.mac_dsn++;
}

/*! set the data sequence number.
 *  @return the current data sequence number.
 */
int8 mac_set_dsn(uint8 dsn)
{
    return pib.mac_dsn = dsn;
}

/*! set the 64-bits extended address of the coordinator.
 *  @param addr the 64-bits address to be set.
 *  @return the result of this operation
 */
int8 mac_set_coord_extended_addr(uint64 addr)
{
    aExtendedAddress = addr;

    return MAC_OK;
}

/*! set the 16-bits short address of the coordinator
 *  @param addr the 16-bits short address to be set
 *  @return the result of this operation.
 */
int8 mac_set_coord_short_addr(uint16 addr)
{
    pib.mac_coord_short_addr = addr;
    return MAC_OK;
} 

/*! get the 64-bits extended address.
 *  @return the 64-bits address.
 */
uint64 mac_get_extended_addr(void)
{
    return aExtendedAddress;
}

/*! get the 16-bits short address of coordiantor.
 *  @return return 16-bits short address of coordiantor.
 */
uint16 mac_get_coord_short_addr(void)
{
    return pib.mac_coord_short_addr;
}

/*! get the 64-bits extended address.
 *  @return return the 64-bits extended address.
 */
uint64 mac_get_coord_extended_addr(void)
{
    return pib.mac_coord_extended_addr;
}

/*! set the 16-bits short address
 *  @param addr the 16-bits address
 *  @return return the result of this operation
 */
int8 mac_set_short_addr(uint16 addr)
{
    pib.mac_short_addr = addr;

    return MAC_OK;
}

/*! get the value of response wait time, which is a constant used
 *  as timeout value when waiting to send the poll request.
 *  @return return the response wait time.
 */
uint16 mac_get_response_wait_time(void)
{
    return pib.mac_response_wait_time;
}

/*! set the value of response wait time.
 *  @param t the value of response wait time to be set.
 *  @return the response wait time.
 */
uint16 mac_set_response_wait_time(uint16 t)
{
    pib.mac_response_wait_time = t;

    return MAC_OK;
}

/*! get the value of max frame totoal wait time, which is a constant used
 *  as the timeout value waiting for the association response. 
 *  @return the value of max frame total wait time constant.
 */
uint16 mac_get_max_frame_total_wait_time(void)
{
    return pib.mac_max_frame_total_wait_time;
}

/*! set the max frame total wait time.
 *  @param t return the max frame total wait time.
 *  @return return the value of max frame total wait time.
 */
uint16 mac_set_max_frame_total_wait_time(uint16 t)
{
    pib.mac_max_frame_total_wait_time = t;
    return pib.mac_max_frame_total_wait_time;
}

/*! generate the 64-bits extended address from a string of bytes.
 *  @param arr pointer to the string of bytes.
 *  @return return the generated 64-bits extended address.
 */
uint64 make_extended_addr(uint8 *arr)
{
    uint64 r;
    uint8 i;
    uint8 *p = (uint8 *)&r;

    for (i = 0; i < 8; i++) {
        *p = *arr;
        p++;
        arr++;
    }

    return r;
}

/*! set the value of transaction persistence time, which is the maximum 
 *  time that a transaction is stored by a coordinator.
 *  @param t the value of time to be set.
 *  @return return the current transaction persistence time.
 */
uint16 mac_set_transaction_persistence_time(uint16 t)
{
    pib.mac_transaction_persistence_time = t;
    return pib.mac_transaction_persistence_time;
}

/*! get the transaction persistence time.
 *  @return return current transaction persistence time.
 */
uint16 mac_get_transaction_persistence_time(void)
{
    return pib.mac_transaction_persistence_time;
}

/*! get the max CSMA backoffs, which is the max backoff times when 
 *  tranmist with CSMA/CA.
 *  @return return the max CSMA backoffs.
 */
uint8 mac_get_max_csma_backoffs(void)
{
    return pib.mac_max_csma_backoffs;
}

/*! set the max csma backoffs.
 *  @return the value of max CSMA backoffs set.
 */
uint8 mac_set_max_csma_backoffs(uint8 n)
{
    pib.mac_max_csma_backoffs = n;

    return pib.mac_max_csma_backoffs;
}

/*! set the max be value, which indicates the maximum length
 *  of backoff time used in CSMA/CA.
 *  @param b the value of max be to be set.
 *  @return return the set value.
 */
uint8 mac_set_max_be(uint8 b)
{
    pib.mac_max_be = b;

    return pib.mac_max_be;
}

/*! get the max be value.
 *  @return return the max be value.
 */
uint8 mac_get_max_be(void)
{
    return pib.mac_max_be;
}

/*! set the min be value, which is the minimum length of the
 *  backoff time used in CSMA/CA.
 *  @param b the min be value to be set.
 *  @return return the set min be value.
 */
uint8 mac_set_min_be(uint8 b)
{
    pib.mac_min_be = b;
    
    return pib.mac_min_be;
}

/*! get the min be value.
 *  @return return the min be value.
 */
uint8 mac_get_min_be(void)
{
    return pib.mac_min_be;
}

/*! set the ack wait duration value, which is the maximum time to wait
 *  for an acknowledgement frame.
 *  @param t the value of ack wait duration to be set.
 *  @return return the set value of ack wait duration.
 */
uint16 mac_set_ack_wait_duration(uint16 t)
{
    pib.mac_ack_wait_duration = t;

    return pib.mac_ack_wait_duration;
}

/*! get the ack wait duration value.
 *  @return return the value of ack wait duration.
 */
uint16 mac_get_ack_wait_duration(void)
{
    return pib.mac_ack_wait_duration;
}

/*! set the max frame retries, which indicates the maximum number
 *  of retries to send a frame to ensure the transmission of the frame.
 *  @param r the value of max frame retries to be set.
 *  @return return the value of max frame retries.
 */
uint8 mac_set_max_frame_retries(uint8 r)
{
    pib.mac_max_frame_retries = r;

    return pib.mac_max_frame_retries;
}

/*! get the max frame retries value.
 *  @return the value of max frame retries.
 */
uint8 mac_get_max_frame_retries(void)
{
    return pib.mac_max_frame_retries;
}

/*! get the short address.
 *  @return the value of short address.
 */
uint16 mac_get_short_addr(void)
{
    return pib.mac_short_addr;
}

/*! get a mcb timer pointer, this timer is used to implement
 *  the timeout mechanism.
 *  @return return the pointer to mcb timer.
 */
mtimer_t *mac_mcb_get_timer(void)
{
    return &mcb.mac_timer;
}

/*! get the superframe value.
 *  @return the value of superframe value.
 */
uint16 mac_get_sup_frm_value(void)
{
    return pib.mac_sup_frm_value;
}

/*! set the superframe order.
 *  @param s the value to be set.
 *  @return return the set superframe order value.
 */
uint8 mac_set_superframe_order(uint8 s)
{
    pib.mac_superframe_order = s;
    return pib.mac_superframe_order;
}

/*! get the superframe order.
 *  @return return the superframe order.
 */
uint8 mac_get_superframe_order(void)
{
    return pib.mac_superframe_order;
}

/*! set the bool value of associated PAN coordinator, which indicates
 *  whether the device is associated to the PAN through PAN coordinator.
 *  @param b the bool value indicates if the node itself is a
 *         associated PAN coordinator.
 *  @return return if the node itself is a associated PAN coordinator.
 */
bool mac_set_associated_pan_coord(bool b)
{
    pib.mac_associated_pan_coord = b;
    return pib.mac_associated_pan_coord;
}

/*! get the value of associated pan coorinator flag.
 *  @return return if the node itself is PAN coordinator.
 */
bool mac_get_associated_pan_coord(void)
{
    return pib.mac_associated_pan_coord;
}

/*! set the beacon order, which specify the transmission interval of the beacon.
 *  @param b the beacon order to be set.
 *  @return return the current beacon order.
 */
uint8 mac_set_beacon_order(uint8 b)
{
    pib.mac_beacon_order = b;
    return pib.mac_beacon_order;
}

/*! get the beacon order.
 *  @return return the beacon order.
 */
uint8 mac_get_beacon_order(void)
{
    return pib.mac_beacon_order;
}

/*! set the association permit flag, which indicates if the current node is
 *  allowing association with other node.
 *  @param b value of the association permit flag.
 *  @return return the current value of association.
 */
bool mac_set_association_permit(bool b)
{
    pib.mac_association_permit = b;
    return pib.mac_association_permit;
}

/*! get the value of association permit flag.
 *  @return teh value of association permit flag.
 */
bool mac_get_association_premit(void)
{
    return pib.mac_association_permit;
}

/*! set the superframe value, which includes the properties of the node.
 *  @param v the value to be set.
 *  @return return the current value of superframe value.
 */
uint16 mac_set_sup_frm_value(uint16 v)
{
    pib.mac_sup_frm_value = v;
    return pib.mac_sup_frm_value;
}
